package munci.old.java;

import munci.old.java.Type.Prim.Num;
import munci.old.know.Dictionary;

public abstract class Type {
	
	public static final Prim
			VOID = new Prim(void.class),
			BOOL = new Prim(boolean.class),
			CHAR = new Prim(char.class);

	public static final Num
			BYTE = new Num(byte.class),
			SHORT = new Num(short.class),
			INT = new Num(int.class),
			LONG = new Num(long.class),
			FLOAT = new Num(float.class),
			DOUBLE = new Num(double.class);

	public abstract Class<?> toClass(Dictionary dict) throws ClassNotFoundException;
	
	public static class Prim extends Type {
		
		private final Class<?> clas;
		
		private Prim(Class<?> clas) {
			this.clas = clas;
		}

		@Override public Class<?> toClass(Dictionary dict) {
			return clas;
		}
		
		@Override public String toString() {
			return clas.toString();
		}
		
		@Override public int hashCode() {
			return clas.hashCode();
		}
		
		@Override public boolean equals(Object obj) {
			return obj == this;
		}
		
		public static class Num extends Prim {
			private Num(Class<?> clas) {
				super(clas);
			}
		} 
	}
	
	public static final Ref ROOT = new Ref(null, "") {

		@Override StringBuilder buildString(StringBuilder str) {
			return str;
		}
		
		@Override public boolean equals(Object obj) {
			return obj == this;
		}
	};
	
	public static class Ref extends Type {
		
		private final Type.Ref prev;
		private final String part;
		
		private Ref(Type.Ref prev, String part) {
			this.prev = prev;
			this.part = part.intern();
		}
		
		public Ref dot(String part) {
			return new Ref(this, part);
		}
		
		public String part() {
			return part;
		}
		
		public Type prev() {
			return prev;
		}
		
		StringBuilder buildString(StringBuilder str) {
			return prev.buildString(str).append('.').append(part);
		}
		
		@Override public String toString() {
			return buildString(new StringBuilder()).substring(1).toString();
		}
		
		@Override public Class<?> toClass(Dictionary dict) throws ClassNotFoundException {
			String name = toString();
			for (;;) {
				try {
					return dict.getClass(name);
				} catch (ClassNotFoundException e) {}
				int dot = name.lastIndexOf('.');
				if (dot < 0) throw new ClassNotFoundException(toString());
				name = name.substring(0, dot) + '$' + name.substring(dot + 1);
			}
		}
		
		@Override public int hashCode() {
			return part.hashCode();
		}
		
		@Override public boolean equals(Object obj)	 {
			return obj instanceof Ref && part == ((Ref) obj).part && prev.equals(((Ref) obj).prev); 
		}
	}
}
